package com.peas.platform.module.icims.expenditure.kpis.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.peas.platform.common.core.enums.BaseEnum;
import com.peas.platform.framework.mybatisplus.domain.BaseDomain;
import com.peas.platform.framework.mybatisplus.po.BasePo;
import com.peas.platform.framework.mybatisplus.service.BaseServiceImpl;
import com.peas.platform.module.icims.base.approve.component.ApproveCallback;
import com.peas.platform.module.icims.base.approve.dto.ApproveDto;
import com.peas.platform.module.icims.base.approve.dto.ApproveOrderNodeDto;
import com.peas.platform.module.icims.base.approve.enums.ApproveOrderBusinessType;
import com.peas.platform.module.icims.base.approve.service.ApproveOrderService;
import com.peas.platform.module.icims.base.approve.service.ApproveService;
import com.peas.platform.module.icims.expenditure.kpis.api.req.SaveExpenditureAdjustmentVo;
import com.peas.platform.module.icims.expenditure.kpis.api.req.SubmitExpenditureAdjustmentVo;
import com.peas.platform.module.icims.expenditure.kpis.controller.vo.ExpenditureAdjustmentItemVo;
import com.peas.platform.module.icims.expenditure.kpis.domain.ExpenditureAdjustmentDomain;
import com.peas.platform.module.icims.expenditure.kpis.dto.ExpenditureAdjustmentDto;
import com.peas.platform.module.icims.expenditure.kpis.dto.ExpenditureAdjustmentItemDto;
import com.peas.platform.module.icims.expenditure.kpis.enums.ExpenditureAdjustmentState;
import com.peas.platform.module.icims.expenditure.kpis.service.ExpenditureAdjustmentItemService;
import com.peas.platform.module.icims.expenditure.kpis.service.ExpenditureAdjustmentService;
import com.peas.platform.module.icims.expenditure.kpis.service.ExpenditureKpiService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;

@Service
public class ExpenditureAdjustmentServiceImpl extends BaseServiceImpl<ExpenditureAdjustmentDto> implements ExpenditureAdjustmentService, ApproveCallback {

    @Resource
    private ExpenditureAdjustmentDomain expenditureAdjustmentDomain;
    @Resource
    private ExpenditureAdjustmentItemService expenditureAdjustmentItemService;
    @Resource
    private ApproveService approveService;
    @Resource
    private ApproveOrderService approveOrderService;
    @Resource
    private ExpenditureKpiService expenditureKpiService;

    @Override
    public BaseDomain<ExpenditureAdjustmentDto, ? extends BasePo> getDomain() {
        return expenditureAdjustmentDomain;
    }

    @Transactional
    @Override
    public ExpenditureAdjustmentDto saveExpenditureAdjustment(SaveExpenditureAdjustmentVo vo) {
        ExpenditureAdjustmentDto ead = BeanUtil.copyProperties(vo, ExpenditureAdjustmentDto.class);
        if (StrUtil.isBlank(ead.getState())) {
            ead.setState(ExpenditureAdjustmentState.save.getKey());
        }
        if (vo.getAdjustAmount().compareTo(BigDecimal.ZERO) < 0) {
            BigDecimal available = expenditureKpiService.queryAvailableAmount(vo.getExpenditureKpiId());
            Assert.isTrue(vo.getAdjustAmount().add(available).compareTo(BigDecimal.ZERO) >= 0, "指标单的可用金额为:" + available);
        }
        int result;
        if (vo.getId() != null) {
            ExpenditureAdjustmentDto bean = this.getById(vo.getId());
            ExpenditureAdjustmentState state = BaseEnum.key2Enum(ExpenditureAdjustmentState.class, bean.getState());
            Assert.isTrue(ExpenditureAdjustmentState.save == state || ExpenditureAdjustmentState.revocation == state || ExpenditureAdjustmentState.reject == state, "调整单[" + bean.getAdjustmentCode() + "]的状态为[" + state.getKey() + "-" + state.getValue() + "]，不允许修改");
            result = this.updateById(ead);
        } else {
            result = this.save(ead);
        }
        Assert.isTrue(result > 0, "保存失败");
        List<ExpenditureAdjustmentItemDto> eaids = expenditureAdjustmentItemService.listByField("expenditureAdjustmentId", ead.getId());
        expenditureAdjustmentItemService.removeBatchByList(eaids);
        // items
        ConcurrentLinkedQueue<String> expenditureEconomicIdSet = new ConcurrentLinkedQueue<>();
        if (CollUtil.isNotEmpty(vo.getItems())) {
            List<ExpenditureAdjustmentItemDto> eaidList = new ArrayList<>();
            CollUtil.forEach(vo.getItems(), (CollUtil.Consumer<ExpenditureAdjustmentItemVo>) (value, index) -> {
                ExpenditureAdjustmentItemDto dto = BeanUtil.copyProperties(value, ExpenditureAdjustmentItemDto.class);
                dto.setExpenditureAdjustmentId(ead.getId());
                eaidList.add(dto);
                Assert.isTrue(!expenditureEconomicIdSet.contains(dto.getExpenditureEconomicId()), "经济分类不能重复");
                expenditureEconomicIdSet.add(dto.getExpenditureEconomicId());
                if (value.getAdjustAmount().compareTo(BigDecimal.ZERO) < 0) {
                    BigDecimal avaible = expenditureKpiService.queryAvailableAmount(vo.getExpenditureKpiId(), value.getExpenditureEconomicId(), false);
                    Assert.isTrue(value.getAdjustAmount().add(avaible).compareTo(BigDecimal.ZERO) >= 0, "指标单对应经济分类的可用金额为:" + avaible);
                }
            });
            expenditureAdjustmentItemService.saveBatch(eaidList);
        }
        return ead;
    }

    @Transactional
    @Override
    public void submitExpenditureAdjustment(SubmitExpenditureAdjustmentVo vo) {
        Assert.notNull(vo.getApproveId(), "请选择审批模版");
        SaveExpenditureAdjustmentVo v = BeanUtil.copyProperties(vo, SaveExpenditureAdjustmentVo.class);
        v.setState(ExpenditureAdjustmentState.submit.getKey());
        v.setItems(vo.getItems());
        ExpenditureAdjustmentDto ead = this.saveExpenditureAdjustment(v);
        ApproveDto ad = approveService.getById(vo.getApproveId());
        approveOrderService.createApproveOrder(ad, BeanUtil.copyToList(vo.getApproveNodes(), ApproveOrderNodeDto.class), ApproveOrderBusinessType.expenditureAdjustment, ead.getId(), ead.getAdjustmentCode(), null, this.getClass());
    }

    @Transactional
    @Override
    public void revocationExpenditureAdjustment(Long id) {
        ExpenditureAdjustmentDto dto = this.getById(id);
        Assert.notNull(dto, "找不到调整单");
        dto.setState(ExpenditureAdjustmentState.revocation.getKey());
        this.updateById(dto);
        approveOrderService.revocationApproveOrder(ApproveOrderBusinessType.expenditureAdjustment, id);
    }

    @Transactional
    @Override
    public void callbackAfterApprove(Long businessId, boolean isPass, boolean isFinalPass) {
        if (businessId == null)
            return;
        if (isPass) {
            if (isFinalPass) {
                ExpenditureAdjustmentDto ead = this.getById(businessId);
                ead.setState(ExpenditureAdjustmentState.pass.getKey());
                this.updateById(ead);
            }
        } else {
            ExpenditureAdjustmentDto ead = this.getById(businessId);
            ead.setState(ExpenditureAdjustmentState.reject.getKey());
            this.updateById(ead);
        }
    }
}
